﻿using NFox.Pycad;
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows.Media.Imaging;

namespace NFox.Pyeditor.ViewModel
{
    public class ModuleViewModel : INotifyPropertyChanged
    {

        public event PropertyChangedEventHandler PropertyChanged;

        public ObservableCollection<ModuleViewModel> Items { get; set; }

        public void NotifyPropertyChanged(string name)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }

        public Module Model { get; }

        public ModuleViewModel(Module model)
        {
            Model = model;
            model.Tag = this;
            model.ModuleChanged += ModuleChanged;
            if (model.IsPackage)
            {
                Package package = model as Package;
                model.ModuleItemsChanged += ModuleItemsChanged;
                Items = new ObservableCollection<ModuleViewModel>();
                foreach (var p in package.Packages)
                    Add(p);
                foreach (var m in package.Modules)
                    Add(m);
                IsExpanded = package.Packages.Count > 0;
            }
        }

        public string Name
        {
            get { return Model.Name; }
            set { Model.Name = value; }
        }

        private void ModuleItemsChanged(Package package, ModuleItemsEventArgs e)
        {
            if (e.Name == "Add")
                Add(e.Item);
            else if (e.Name == "Remove")
                Remove(e.Item);
            NotifyPropertyChanged("Items");
        }

        private void Remove(Module item)
        {
            Items.Remove(item.Tag);
        }

        public void Add(Module item)
        {
            var wrap = new ModuleViewModel(item);
            int low = 0, high = Items.Count - 1;
            while (low <= high)
            {
                int middle = (low + high) / 2;
                switch (Compare(wrap, Items[middle]))
                {
                    case 1:
                        low = middle + 1;
                        break;
                    case 0:
                        return;
                    case -1:
                        high = middle - 1;
                        break;
                }
            }
            Items.Insert(low, wrap);
        }

        private int Compare(ModuleViewModel m1, ModuleViewModel m2)
        {
            int res = m1.Model.Level.CompareTo(m2.Model.Level);
            return res == 0 ? m1.Name.CompareTo(m2.Name) : res;
        }

        private void ModuleChanged(Module module, ModuleEventArgs e)
        {
            NotifyPropertyChanged(e.Name);
            if(e.Name == "Name")
            {
                if (module.Document != null)
                    module.Document.Title = module.Name;
            }
        }

        public virtual BitmapImage Icon
        {
            get
            {
                string format = "pack://application:,,,/NFox.Pyeditor;component/Images/{0}.png";
                if (Model.IsModule)
                    return new BitmapImage(new Uri(string .Format(format, "Module"))); 
                else if (Model.IsProject)
                    return new BitmapImage(new Uri(string.Format(format, "Project")));
                else if (Model is SpecPackage)
                    return new BitmapImage(new Uri(string.Format(format, "Spec")));
                return new BitmapImage(new Uri(string.Format(format, "Package")));
            }
        }

        bool _isexpanded;
        public bool IsExpanded
        {
            get { return _isexpanded; }
            set
            {
                if (_isexpanded != value)
                {
                    _isexpanded = value;
                    NotifyPropertyChanged("IsExpanded");
                }
            }
        }

        public bool Visible { get { return Model.Visible; } }

        public int Depth
        {
            get
            {
                int n = 0;
                var p = Model.Parent;
                while (p != null)
                {
                    p = p.Parent;
                    n++;
                }
                return n;
            }
        }

        public bool IsPackage { get { return Model.IsPackage; } }

        public bool IsProject { get { return Model.IsProject && ((Project)Model).Type == Project.ProjectType.Package; } }

    }
}
